let tokenTypes = require('../common/token-types');
let astModule = require('../modules/ast-module');
let nodeUtil = require('../common/node-util');

let expressionParser = {
  result: {},
  nodeStack: [],
  operatorStack: [],
  parse(tokens) {
    tokens.forEach((token, index) => {
      if (this.isTokenLiteral(token)) {
        if (this.operatorStack.length == 0) {
          this.nodeStack.push({
            index,
            value: nodeUtil.genLiteralNode(token)
          });
        } else {
          let lastOpera = this.operatorStack[this.operatorStack.length - 1];
          // 判断当前运算符栈栈顶运算符的优先级
          if ([tokenTypes.ASSIGN, tokenTypes.POINT].includes(lastOpera.type)) {
            // 遇到高优先级运算符，将此节点压栈
            this.nodeStack.push({
              index,
              value: nodeUtil.genLiteralNode(token)
            });
          } else {
            // 遇到低优先级运算符，直接生成新节点并压栈
            let left = this.nodeStack.pop();
            let operator = this.operatorStack.pop();
            let right = {
              index,
              value: nodeUtil.genLiteralNode(token)
            };
            this.nodeStack.push({
              index,
              value: this.genNodeForExp(left, right, operator)
            });
          }
        }
      } else if (token.type == tokenTypes.ASSIGN) {
        this.operatorStack.push(token);
      } else {
        this.operatorStack.push(token);
      }
    });
    if (this.operatorStack.length > 0) {
      let right = this.nodeStack.pop();
      let left = this.nodeStack.pop();
      let operator = this.operatorStack.pop();
      this.result = this.genNodeForExp(left, right, operator);
    } else {
      // 针对show命令 : 5 / 5.name
      if (this.nodeStack.length > 0) {
        this.result = this.nodeStack.pop().value;
      }
    }
    return this.result;
  },
  isTokenLiteral(token) {
    return [tokenTypes.WORD, tokenTypes.DIGIT, tokenTypes.URI, tokenTypes.EXPRESSION].includes(token.type);
  },
  genNodeForExp(left, right, operator) {
    let tag = nodeUtil.getExpTag(operator);
    let start = nodeUtil.isNodeLiteral(left.value) ? left.index : left.value.startToken;
    let end = nodeUtil.isNodeLiteral(right.value) ? right.index + 1 : right.value.endToken;
    left = left.value;
    right = right.value;
    let leftChild = nodeUtil.isNodeLiteral(left) ? [left.value] : left.children;
    let rightChild = nodeUtil.isNodeLiteral(right) ? [right.value] : right.children;
    let children = leftChild.concat([operator].concat(rightChild));
    return new astModule.Expression(tag, left, right, operator, children, start, end);
  }
};

module.exports = expressionParser;
